import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Map } from 'ol';
import * as _ from 'lodash';
import Feature from 'ol/Feature';
import View from 'ol/View';
import { IGC } from 'ol/format';
import { LineString, Point } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import OSM, { ATTRIBUTION } from 'ol/source/OSM';
import VectorSource from 'ol/source/Vector';
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';
import { Draw } from 'ol/interaction';
import XYZ from 'ol/source/XYZ';
import {fromLonLat, transform} from 'ol/proj';
import { unByKey } from 'ol/Observable';
import { UtilComponent } from '../../interface/util-component.interface';

@Component({
  selector: 'kylin-movement-path',
  templateUrl: './movement-path.component.html',
  styleUrls: ['./movement-path.component.less']
})
export class MovementPathComponent implements OnInit, OnChanges, UtilComponent {
  // ---------- 接口实现 begin -------------- //
  hasContent = true;
  map: Map;

  @Input() set data(val) {
    Object.assign(this, val);
  };

  // ---------- 接口实现 end ---------------- //
  currentLayer = null;
  currentEvent = null;

  constructor() { }

  ngOnInit() {
  }
  ngOnChanges(changes: SimpleChanges): void {
    if (!_.isEmpty(changes.map.currentValue)) {

    }
  }

  add() {
    this.currentEvent = {};
    const colors = {
      'Clement Latour': 'rgba(0, 0, 255, 0.7)',
      'Damien de Baesnt': 'rgba(0, 215, 255, 0.7)',
      'Sylvain Dhonneur': 'rgba(0, 165, 255, 0.7)',
      'Tom Payne': 'rgba(0, 255, 255, 0.7)',
      'Ulrich Prinz': 'rgba(0, 215, 255, 0.7)'
    };

    const styleCache = {};

    const styleFunction = (feature) => {
      const color = colors[feature.get('PLT')];
      let style = styleCache[color];
      if (!style) {
        style = new Style({
          stroke: new Stroke({
            color: color,
            width: 3
          })
        });
        styleCache[color] = style;
      }
      return style;
    };

    const vectorSource = new VectorSource();
    const igcUrls = [
      '/assets/data/igc/Clement-Latour.igc',
      '/assets/data/igc/Damien-de-Baenst.igc',
      '/assets/data/igc/Sylvain-Dhonneur.igc',
      '/assets/data/igc/Tom-Payne.igc',
      '/assets/data/igc/Ulrich-Prinz.igc'
    ];
    function get(url, callback) {
      const client = new XMLHttpRequest();
      client.open('GET', url);
      client.onload = () => {
        callback(client.responseText);
      };
      client.send();
    }
    const igcFormat = new IGC();
    for (let i = 0; i < igcUrls.length; ++i) {
      get(igcUrls[i], (data) => {
        const features = igcFormat.readFeatures(data,
          { featureProjection: 'EPSG:3857' });
        vectorSource.addFeatures(features);
      });
    }
    const time = {
      start: Infinity,
      stop: -Infinity,
      duration: 0
    };

    vectorSource.on('addfeature', (event) => {
      const geometry = event.feature.getGeometry();
      time.start = Math.min(time.start, geometry['getFirstCoordinate']()[2]);
      time.stop = Math.max(time.stop, geometry['getLastCoordinate']()[2]);
      time.duration = time.stop - time.start;
    });

    const map = this.map;
    this.currentLayer = new VectorLayer({
      source: vectorSource,
      style: styleFunction
    });
    this.map.addLayer(this.currentLayer);
    this.map.getView().animate({ center: transform([703365.7089403362, 5714629.865071137], 'EPSG:3857', 'EPSG:3857') }, { zoom: 9 });

    let point = null;
    let line = null;
    const displaySnap = (coordinate) => {
      const closestFeature = vectorSource.getClosestFeatureToCoordinate(coordinate);
      const info = document.getElementById('info');
      if (closestFeature === null) {
        point = null;
        line = null;
        info.innerHTML = '&nbsp;';
      } else {
        const geometry = closestFeature.getGeometry();
        const closestPoint = geometry.getClosestPoint(coordinate);
        if (point === null) {
          point = new Point(closestPoint);
        } else {
          point.setCoordinates(closestPoint);
        }
        const date = new Date(closestPoint[2] * 1000);
        info.innerHTML =
          closestFeature.get('PLT') + ' (' + date.toLocaleDateString() + ')';
        const coordinates = [coordinate, [closestPoint[0], closestPoint[1]]];
        if (line === null) {
          line = new LineString(coordinates);
        } else {
          line.setCoordinates(coordinates);
        }
      }
      map.render();
    };

    this.currentEvent.pointermove = map.on('pointermove', (evt) => {
      if (evt.dragging) {
        return;
      }
      const coordinate = map.getEventCoordinate(evt.originalEvent);
      displaySnap(coordinate);
    });

    this.currentEvent.click = map.on('click', (evt) => {
      displaySnap(evt.coordinate);
    });

    const stroke = new Stroke({
      color: 'rgba(255,0,0,0.9)',
      width: 1
    });
    const style = new Style({
      stroke: stroke,
      image: new CircleStyle({
        radius: 5,
        fill: null,
        stroke: stroke
      })
    });
    this.currentEvent.postcompose = map.on('postcompose', (evt) => {
      const vectorContext = evt.vectorContext;
      vectorContext.setStyle(style);
      if (point !== null) {
        vectorContext.drawGeometry(point);
      }
      if (line !== null) {
        vectorContext.drawGeometry(line);
      }
    });

    const featureOverlay = new VectorLayer({
      source: new VectorSource(),
      map: map,
      style: new Style({
        image: new CircleStyle({
          radius: 5,
          fill: new Fill({
            color: 'rgba(255,0,0,0.9)'
          })
        })
      })
    });

    document.getElementById('time').addEventListener('input', () => {
      const value = parseInt(document.getElementById('time')['value'], 10) / 100;
      const m = time.start + (time.duration * value);
      vectorSource.forEachFeature((feature) => {
        const geometry = /** @type {module:ol/geom/LineString~LineString} */ (feature.getGeometry());
        const coordinate = geometry['getCoordinateAtM'](m, true);
        let highlight = feature.get('highlight');
        if (highlight === undefined) {
          highlight = new Feature(new Point(coordinate));
          feature.set('highlight', highlight);
          featureOverlay.getSource().addFeature(highlight);
        } else {
          highlight.getGeometry().setCoordinates(coordinate);
        }
      });
      map.render();
    });


  }

  cancel(options?: any): any {
    this.map.removeLayer(this.currentLayer);
    this.currentLayer = null;
    this.map.getView().animate({ center: fromLonLat([108.943904, 34.319323]) }, { zoom: 5 }); // 先移动再放大
    _.forIn(this.currentEvent, (value, key) => {
      unByKey(value);
    })
  }
}
